package com.ts.api.module.channel.controller;

import com.gitee.apanlh.annotation.viewresolver.RequestParamVo;
import com.gitee.apanlh.util.base.ChooseEq;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.valid.IdcardUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.vo.RequestVO;
import com.gitee.apanlh.web.model.vo.ResultVO;
import com.ts.api.common.constant.BizEnum;
import com.ts.api.common.constant.LoginConstant;
import com.ts.api.common.constant.channel.ChannelRegisterFieldEnum;
import com.ts.api.common.constant.channel.ChannelUserStatus;
import com.ts.api.common.constant.common.SwitchEnum;
import com.ts.api.common.context.ChannelContext;
import com.ts.api.common.context.ChannelRequestContext;
import com.ts.api.common.context.ChannelUserContext;
import com.ts.api.common.entity.AjaxResult;
import com.ts.api.common.localcache.DistrictCache;
import com.ts.api.common.redis.UserRedisKey;
import com.ts.api.exp.BizException;
import com.ts.api.module.app.user.entity.vo.RespAppUserVO;
import com.ts.api.module.channel.entity.ChannelRegisterField;
import com.ts.api.module.channel.entity.ChannelRequest;
import com.ts.api.module.channel.entity.bo.ChannelRegisterFieldBO;
import com.ts.api.module.channel.entity.bo.ChannelUserBO;
import com.ts.api.module.channel.entity.cache.ChannelCacheUser;
import com.ts.api.module.channel.entity.po.ChannelFlowConfigPO;
import com.ts.api.module.channel.entity.po.ChannelUserFormPO;
import com.ts.api.module.channel.entity.po.ChannelUserRegisterPO;
import com.ts.api.module.channel.entity.qo.ChannelUserQO;
import com.ts.api.module.channel.entity.vo.ReqChannelRegisterFieldVO;
import com.ts.api.module.channel.entity.vo.ReqChannelRegisterVO;
import com.ts.api.module.channel.service.ChannelConfigService;
import com.ts.api.module.channel.service.ChannelFormService;
import com.ts.api.module.channel.service.ChannelLoginService;
import com.ts.api.module.channel.service.ChannelRegisterFieldService;
import com.ts.api.module.channel.service.ChannelUserService;
import com.ts.api.module.channel.service.DoubleWriteUserService;
import com.ts.api.module.common.entity.DistrictPO;
import com.ts.api.module.common.service.UserRealAuthService;
import com.ts.cache.form.entity.FormCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  获取渠道注册相关
 */
@RestController
@RequestMapping("/channel/register")
public class ChannelRegisterController {

    @Autowired
    private ChannelRegisterFieldService channelRegisterFieldService;
    @Autowired
    private ChannelUserService channelUserService;
    @Autowired
    private ChannelLoginService loginService;
    @Autowired
    private UserRealAuthService userRealAuthService;
    @Autowired
    private DoubleWriteUserService doubleWriteUserService;
    @Autowired
    private ChannelFormService channelFormService;
    @Autowired
    private ChannelConfigService channelConfigService;

    /**
     *  根据手机号md5置换token
     *
     *  @return AjaxResult
     */
    @GetMapping("/getToken")
    public ResultVO<Object> getToken(@RequestParamVo RequestVO requestVO, HttpServletResponse response) {
        ChannelUserRegisterPO userRegisterPO = requestVO.toBean(ChannelUserRegisterPO.class);
        if (ValidParam.isNull(userRegisterPO) || ValidParam.isEmpty(userRegisterPO.getPhoneMd5())) {
            return ResultVO.fail("非法获取");
        }

        ChannelUserQO channelUserQO = ChannelUserQO.createPhoneMd5(userRegisterPO.getPhoneMd5());
        ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(channelUserQO);
        if (ValidParam.isNull(channelUserRegisterPO)) {
            return ResultVO.fail("非法获取2");
        }

        String token = loginService.createToken(ChannelCacheUser.create(channelUserRegisterPO.getId(), channelUserRegisterPO.getPhone()));
        response.addHeader(LoginConstant.RESP_HEADER_TOKEN, token);
        return ResultVO.suc();
    }

    /**
     *  获取用户信息个人接口
     *
     *  @return ResultVO
     */
    @GetMapping("/get")
    public ResultVO<Object> get() {
        ChannelCacheUser cacheUser = ChannelUserContext.get();
        ChannelUserRegisterPO channelUserRegisterPO = channelUserService.get(ChannelUserQO.createPhone(cacheUser.getPhone()));
        return ResultVO.suc(CopyUtils.copy(channelUserRegisterPO, RespAppUserVO.class));
    }

    /**
     * 获取渠道动态注册字段列表
     *
     * @return AjaxResult
     */
    @GetMapping("/list/field")
    public AjaxResult list() {
        List<ChannelRegisterField> list = channelRegisterFieldService.list(ChannelContext.getId());
        return AjaxResult.success(list);
    }

    /**
     * 用户注册
     *
     * @param  requestVO
     * @param  response
     * @return AjaxResult
     */
    @PostMapping("/user")
    public AjaxResult registerUser(@RequestParamVo RequestVO requestVO, HttpServletResponse response) {
        //  用户注册信息
        ReqChannelRegisterVO reqChannelRegisterVO = requestVO.toBean(ReqChannelRegisterVO.class);
        if (ValidParam.isNull(reqChannelRegisterVO) || ValidParam.isEmpty(reqChannelRegisterVO.getListRegisterField())) {
            BizException.fastFail(BizEnum.EMPTY);
        }

        String smsCode = reqChannelRegisterVO.getSmsCode();
        List<ReqChannelRegisterFieldVO> listReqChannelRegisterFieldVO = reqChannelRegisterVO.getListRegisterField();

        //  检测参数是否存在
        List<ChannelRegisterField> listChannelRegisterField = channelRegisterFieldService.list(ChannelContext.getId());
        channelRegisterFieldService.checkFieldParam(listReqChannelRegisterFieldVO, listChannelRegisterField);

        //  转化属性
        ChannelRegisterFieldBO registerFieldBO = ChannelRegisterFieldBO.convertField(listReqChannelRegisterFieldVO, listChannelRegisterField);

        //  用户注册
        ChannelUserBO userFlowBO = channelUserService.register(smsCode, registerFieldBO, true);

        String token = loginService.createToken(ChannelCacheUser.create(userFlowBO.getUserId(), userFlowBO.getPhone()));
        response.addHeader(LoginConstant.RESP_HEADER_TOKEN, token);

        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        return AjaxResult.success("注册成功", result);
    }

    /**
     *  用户更新
     *
     *  @return AjaxResult
     */
    @PostMapping("/update")
    public AjaxResult update(@RequestParamVo RequestVO requestVO) {
        ChannelUserRegisterPO userRegisterPO = requestVO.toBean(ChannelUserRegisterPO.class);
        if (ValidParam.isNull(userRegisterPO)) {
            BizException.fastFail(BizEnum.EMPTY);
        }

        //  校验城市
        if (ValidParam.isEmpty(userRegisterPO.getAreaCode()) || ValidParam.isEmpty(userRegisterPO.getAreaName())) {
            BizException.fastFail(BizEnum.EMPTY);
        }
        //  前端传的城市名称有可能是简写，要转一下，避免分发的时候造成问题
        DistrictPO districtPO = DistrictCache.getByName(userRegisterPO.getAreaName());
        userRegisterPO.setAreaCode(districtPO.getCode());
        userRegisterPO.setAreaName(districtPO.getName());

        //  获取当前的请求对象
        ChannelRequest channelRequest = ChannelRequestContext.get();
        //  当前渠道id
        Long channelId = ChannelContext.getId();
        //  当前用户id
        Long userId = ChannelUserContext.getId();
        userRegisterPO.setId(userId);

        //  获取渠道注册字段
        List<ChannelRegisterField> listChannelRegisterField = channelRegisterFieldService.list(channelId);
        List<ChannelRegisterField> findUserName = CollUtils.find(listChannelRegisterField, t -> Eq.str(t.getMappingName(), ChannelRegisterFieldEnum.USER_NAME.getMappingName()));
        List<ChannelRegisterField> findIdcard = CollUtils.find(listChannelRegisterField, t -> Eq.str(t.getMappingName(), ChannelRegisterFieldEnum.IDCARD.getMappingName()));

        if (ValidParam.isNotEmpty(findUserName) && ValidParam.isEmpty(userRegisterPO.getUserName())) {
            BizException.fastFail(BizEnum.EMPTY);
        }

        if (ValidParam.isNotEmpty(findIdcard) && ValidParam.isEmpty(userRegisterPO.getIdcard())) {
            BizException.fastFail(BizEnum.EMPTY);
        }

        //  是否开启二要素认证
        if (ValidParam.isNotEmpty(findUserName) && ValidParam.isNotEmpty(findIdcard)) {
            String idcard = userRegisterPO.getIdcard();
            // 基础身份验证
            boolean valid = IdcardUtils.valid(idcard);
            if (!valid) {
                return AjaxResult.error("认证失败,请输入正确的身份证");
            }

            //  验证渠道是否二要素验证
            ChannelFlowConfigPO channelFlowConfigPO = channelConfigService.getFlowConfigByChannelId();
            if (SwitchEnum.hasEnable(channelFlowConfigPO.getEnableTwoElement())) {
                //  二要素认证
                Boolean nameAndIdcardFlag = userRealAuthService.nameAndIdcard(userRegisterPO.getUserName(), userRegisterPO.getIdcard());
                //  更新二要素校验状态
                if (nameAndIdcardFlag) {
                    userRegisterPO.setTwoElementStatus(1);
                } else {
                    userRegisterPO.setTwoElementStatus(0);
                }
                userRegisterPO.setIp(channelRequest.getIp());
                doubleWriteUserService.updateUser(userRegisterPO);

                if (!nameAndIdcardFlag) {
                    return AjaxResult.error("认证失败,请输入正确的身份信息");
                }
            }

            //  获取身份证性别
            String idcardSex = IdcardUtils.getGender(idcard);
            String sex = ChooseEq.create(idcardSex)
                    .when("男", "0")
                    .when("女", "1")
                    .end();
            userRegisterPO.setSex(sex);

            //  获取用户年龄表单
            Integer userAge = IdcardUtils.getAge(idcard);
            FormCache ageFormCache = channelFormService.getFormMappingValue("age", userAge.toString());

            //  插入用户表单信息
            List<ChannelUserFormPO> listUserForm = CollUtils.newArrayList();
            ChannelUserFormPO userFormPO = new ChannelUserFormPO();
            userFormPO.setUserId(userRegisterPO.getId());
            userFormPO.setChannelId(channelId);
            userFormPO.setFormFieldId(ageFormCache.getFormFieldId());
            userFormPO.setFormFieldValueId(ageFormCache.getFormFieldValueId());
            userFormPO.setCreateTime(DateUtils.currentTime());
            listUserForm.add(userFormPO);

            //  更新用户年龄
            doubleWriteUserService.batchInsertUserForm(listUserForm);
        }

        //  如果身份证为空且存在年龄字段
        Object age = requestVO.get("age");
        if (ValidParam.isEmpty(findIdcard) && ValidParam.isNotNull(age)) {
            Integer ageInt = ClassConvertUtils.toInt(age);
            FormCache ageFormCache = channelFormService.getFormMappingValue("age", ageInt.toString());

            //  插入用户表单信息
            List<ChannelUserFormPO> listUserForm = CollUtils.newArrayList();
            ChannelUserFormPO userFormPO = new ChannelUserFormPO();
            userFormPO.setUserId(userRegisterPO.getId());
            userFormPO.setChannelId(channelId);
            userFormPO.setFormFieldId(ageFormCache.getFormFieldId());
            userFormPO.setFormFieldValueId(ageFormCache.getFormFieldValueId());
            userFormPO.setCreateTime(DateUtils.currentTime());
            listUserForm.add(userFormPO);

            //  更新用户年龄
            doubleWriteUserService.batchInsertUserForm(listUserForm);
        }

        //  更新用户ip
        userRegisterPO.setIp(channelRequest.getIp());
        doubleWriteUserService.updateUser(userRegisterPO);
        return AjaxResult.success();
    }

    /**
     *  更新Ip(联登成功获取到tocken后调用)
     *
     *  @return AjaxResult
     */
    @PostMapping("/updateIp")
    public AjaxResult updateIp() {
        //  获取当前的请求对象
        ChannelRequest channelRequest = ChannelRequestContext.get();
        //  当前用户id
        Long userId = ChannelUserContext.getId();

        ChannelUserRegisterPO userRegisterPO = new ChannelUserRegisterPO();
        userRegisterPO.setId(userId);
        userRegisterPO .setIp(channelRequest.getIp());
        userRegisterPO.setBrowserName(channelRequest.getUserAgent().getBrowser().getName());
        userRegisterPO.setOsName(channelRequest.getUserAgent().getOperatingSystem().getName());
        userRegisterPO.setDeviceType(channelRequest.getUserAgent().getOperatingSystem().getDeviceType().getName());
        doubleWriteUserService.updateUser(userRegisterPO);
        return AjaxResult.success();
    }

    /**
     *  用户退出接口
     *
     *  @return ResultVO
     */
    @PostMapping("/logout")
    public ResultVO<Object> logout() {
        //  删除token
        UserRedisKey.LOGIN_TOKEN.delKey(ChannelUserContext.get().getPhone());
        return ResultVO.suc("退出成功");
    }

    /**
     *  用户注销接口
     *
     *  @return ResultVO
     */
    @PostMapping("/cancel")
    public ResultVO<Object> cancel() {
        ChannelUserRegisterPO userRegisterPO = new ChannelUserRegisterPO();
        userRegisterPO.setId(ChannelUserContext.getId());
        userRegisterPO.setStatus(ChannelUserStatus.CANCEL.getStatus());
        doubleWriteUserService.updateUser(userRegisterPO);

        //  删除token
        UserRedisKey.LOGIN_TOKEN.delKey(ChannelUserContext.get().getPhone());
        return ResultVO.suc("注销成功");
    }

}
